#include "ET++.ph"
#ifdef __GNUG__
#pragma implementation
#endif

#include "FindDialog.h"

#include "Class.h"
#include "RegularExp.h"
#include "BorderItems.h"
#include "Box.h"
#include "Fields.h"
#include "Buttons.h"
#include "TextView.h"
#include "Alert_e.h"
#include "FindChange_e.h"
#include "String.h"

//---- FindDialog --------------------------------------------------------------

NewMetaImpl(FindDialog, Dialog, (TP(rex), TP(tvp), TP(ei1), TB(atEnd),
				TB(atBegin), TP(modecl), TP(optionscl)));

FindDialog::FindDialog(const char *title) : Dialog(title, eWinFixed)
{
	tvp= 0;
	rex= new RegularExp;
	atEnd= atBegin= FALSE;
}

FindDialog::~FindDialog()
{
	SafeDelete(rex);
}

void FindDialog::SetTextViewFocus(TextView *tv)
{
	tvp= tv;
}

TextView *FindDialog::GetTextViewFocus()
{
	return tvp;
}

VObject *FindDialog::DoMakeControls()
{
	return
		new VExpander(10,
			new Form("Find:", ei1= new TextField(cIdFind, 15), 0),
			new HExpander(10,
				new BorderItem("Direction",
					modecl= new OneOfCluster(cIdFindMode,
						"Forward",
						"Backward",
						0
					)
				),
				new BorderItem("Options",
					optionscl= new ManyOfCluster(cIdFindOpt,
						"Ignore Case",
						"Match Whole Word",
						0
					)
				),
				0
			),
			0
		);
}

VObject *FindDialog::DoMakeActions()
{
	return
		new HBox(10, (VObjAlign)(eVObjVBase|eVObjHGapExpand),
			find= new ActionButton(cIdDoFind,           "Find Next", TRUE),
			new ActionButton(cIdCancel, "Close"),
			0
		);
}

void FindDialog::DoSetDefaults()
{
	// copy selection in associated TextView as default value
	if (tvp->HasSelection()) {
		int from, to;
		tvp->GetSelection(&from, &to);
		if (tvp->CharToLine(from) == tvp->CharToLine(to)) {
			byte buf[1000];
			tvp->GetText()->CopyInStr(buf, sizeof buf, from, to);
			ei1->SetString((char*)buf, TRUE);
		}
	}
}

void FindDialog::DoSetup()
{
	find->Enable(ei1->GetTextSize() > 0);
}

void FindDialog::Control(int id, int p, void *v)
{
	if (id == cIdDoFind) {
		DoFind(ei1->GetString(), modecl->GetCurrentItem() == cIdForward);
		tvp->RevealSelection();
		return;
	}
	Dialog::Control(id, p, v);
}

void FindDialog::SendDown(int, int part, void *v)
{
	if (part == cPartSelectionChanged) {
		if (((Object*)v)->IsKindOf(TextView)) {
			TextView *tv= (TextView*)v;
			FindChange::SetFocus(tv);
		}
	}
}

bool FindDialog::Compile(const char *pattern)
{
	char searchpattern[1000];
	if (optionscl->IsItemOn(cIdMatchWord))
		strn0cpy(searchpattern, form((char*)rex->MatchWordPattern(), pattern), sizeof searchpattern);
	else
		strcpy(searchpattern, pattern);
		
	rex->Reset(searchpattern, optionscl->IsItemOn(cIdIgnCase));
	if (rex->GetExprState()) {
		ShowAlert(eAlertNote, rex->GetExprState());
		return FALSE;
	}
	return TRUE;
}

void FindDialog::FindAgain()
{
	if (strlen(ei1->GetString()) == 0)
		return;
	DoFind(ei1->GetString(), modecl->GetCurrentItem() == cIdForward);
	tvp->RevealSelection();
}

const char *FindDialog::GetSearchPattern()
{
	return ei1->GetString();
}

bool FindDialog::DoFind(const char *pattern, bool direction, bool msg)
{
	bool found;

	if (atEnd) {
		tvp->Home();
		atEnd= FALSE;
	}
	if (atBegin) {
		tvp->Bottom();
		atBegin= FALSE;
	}
	if (!Compile(pattern))
		return FALSE;
	found= tvp->SelectRegExpr(rex, direction);
	if (!found && msg) {
		ShowAlert(eAlertNote, "\"%s\" not found", pattern);
		if (direction)
			atEnd= TRUE;
		else
			atBegin= TRUE;
	}
	return found;
}

